//go:build integration

package test

import (
	"context"
	"runtime/debug"
	"testing"
	"time"
	"v8s/test/containers/k3s"
	mongodb "v8s/test/containers/mongodb"

	"v8s-controller/test/support"
	task_synchronization "v8s-controller/test/task-synchronization"

	"v8s/logger"
)

type (
	suit struct {
		folder string
	}
)

func TestFeatures(t *testing.T) {
	logger.BuildLogger(logger.Properties{Encoder: logger.ConsoleEncoder, Level: logger.DebugLevel})

	// Arrange
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)

	mongo := mongodb.StartContainer(ctx)
	defer mongo.Terminate(context.Background())

	kubernetes := k3s.StartContainer(ctx)
	defer kubernetes.Terminate(context.Background())

	applicationContext := support.GetApplicationContext(ctx, mongo, kubernetes)

	cancel()

	// Act
	suits := []suit{
		{"invisible--all-tasks-deleted"},
		{"invisible--all-tasks-error"},
		{"invisible--all-tasks-suspended"},
		{"invisible--locked--not-seen"},
		{"invisible--locked--seen-long-ago"},
		{"invisible--locked--seen-recently"},
		{"invisible--tasks-with-mixed-statuses"},
		{"invisible--unlocked--seen-recently"},
		{"old-lock--not-seen--existing-tasks"},
		{"old-lock--not-seen--new-tasks"},
		{"old-lock--seen-long-ago--existing-tasks"},
		{"old-lock--seen-long-ago--new-tasks"},
		{"task-with-deadlined-provisioning-0-instances"},
		{"task-with-deadlined-provisioning-2-instances"},
		{"task-with-error-compose"},
		{"task-with-error-compose-with-valid"},
		{"unlocked--not-seen--existing-tasks"},
		{"unlocked--not-seen--new-tasks"},
		{"unlocked--seen-long-ago--existing-tasks"},
		{"unlocked--seen-long-ago--new-tasks"},
	}

	for _, current := range suits {
		t.Run(current.folder, cleaned(applicationContext, safe(applicationContext, func(t *testing.T, ctx *support.ApplicationContext) {
			task_synchronization.Test(t, ctx, current.folder)
		})))
	}
}

func cleaned(ctx *support.ApplicationContext, block func(t *testing.T)) func(t *testing.T) {
	ctx.K8SHelper.Clear(context.Background())
	ctx.MongoHelper.Clear(context.Background())

	return block
}

func safe(ctx *support.ApplicationContext, block func(*testing.T, *support.ApplicationContext)) func(t *testing.T) {
	return func(t *testing.T) {
		defer func() {
			recovered := recover()
			if recovered != nil {
				debug.PrintStack()
				t.Error(recovered)
			}
		}()

		block(t, ctx)
	}
}
